package com.gwtgeo.ui.client.mvp.desktop;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.widget.WidgetDisplay;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import com.gwtgeo.service.core.utils.SimpleIdGenerator;
import com.gwtgeo.ui.client.gin.GwtgeoGinFactory;
import com.gwtgeo.ui.client.mvp.map.MapPresenter;
import com.gwtgeo.ui.client.mvp.windowsmanager.RecoversWinData;
import com.gwtgeo.ui.client.mvp.windowsmanager.WindowTypeEnum;
import com.gwtgeo.ui.shared.event.OpenWinModalEvent;
import com.gwtgeo.ui.shared.event.RegisterViewEvent;
import com.gwtgeo.ui.shared.event.ShowViewEvent;
import com.gwtgeo.ui.shared.rpc.SaveDef;
import com.gwtgeo.ui.shared.rpc.SaveDefResult;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.menu.events.ClickHandler;
import com.smartgwt.client.widgets.menu.events.HasClickHandlers;
import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent;

public class DesktopPresenter extends WidgetPresenter<DesktopPresenter.Display>
		implements RecoversWinData {

	private static SimpleIdGenerator idGenerator = new SimpleIdGenerator();

	private final DispatchAsync dispatcher;

	class MenuItemDescriptor {

		private String id;
		private String label;
		private WindowTypeEnum type;
		private HasClickHandlers menuItem;

		public MenuItemDescriptor(String label, WindowTypeEnum type) {
			super();
			this.id = new Integer(idGenerator.next()).toString();
			this.label = label;
			this.type = type;
		}

		public String getLabel() {
			return label;
		}

		public void setLabel(String label) {
			this.label = label;
		}

		public HasClickHandlers getMenuItem() {
			return menuItem;
		}

		public void setMenuItem(HasClickHandlers menuItem) {
			this.menuItem = menuItem;
		}

		public WindowTypeEnum getType() {
			return type;
		}

		public String getId() {
			return id;
		}
	}

	public interface Display extends WidgetDisplay {
		void addMenu(String name, List<MenuItemDescriptor> descriptors);

		Canvas getWorkArea();

		void disableMenuItems(List<String> ids);

		void enableMenuItems(List<String> ids);

		void disableMenuButton(List<String> names);

		void enableMenuButton(List<String> names);
	}

	private List<MenuItemDescriptor> viewDescriptors;

	private List<MenuItemDescriptor> fileMenuDescriptors;

	@Inject
	public DesktopPresenter(Display display, EventBus eventBus,
			DispatchAsync dispatcher) {
		super(display, eventBus);
		this.defineFileMenu();
		this.defineViews();
		this.dispatcher = dispatcher;
	}

	private void defineFileMenu() {
		fileMenuDescriptors = new ArrayList<MenuItemDescriptor>();
		fileMenuDescriptors.add(new MenuItemDescriptor("New Map",
				WindowTypeEnum.NEW));
		fileMenuDescriptors.add(new MenuItemDescriptor("Load Map",
				WindowTypeEnum.LOAD));
		MenuItemDescriptor saveMap = new MenuItemDescriptor("Save Map", null);
				fileMenuDescriptors.add(saveMap);
		fileMenuDescriptors.add(new MenuItemDescriptor("Save Map as",
				WindowTypeEnum.SAVE_AS));
		display.addMenu("File", fileMenuDescriptors);
		saveMap.getMenuItem().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(MenuItemClickEvent event) {
				// TODO PMA20100509 Think.
				final MapPresenter mapPresenter = GwtgeoGinFactory.injector
						.getMapPresenter();
				dispatcher.execute(new SaveDef(mapPresenter.getName(),
						mapPresenter.buildSaveableModel()),
						new AsyncCallback<SaveDefResult>() {

							@Override
							public void onFailure(Throwable caught) {
								// TODO PMA20100320 handle error.
							}

							@Override
							public void onSuccess(SaveDefResult result) {
								SC.say("Project " + mapPresenter.getName()
										+ " successfully saved.");
							}

						});
			}
		});
	}

	private void defineViews() {

		viewDescriptors = new ArrayList<MenuItemDescriptor>();
		viewDescriptors.add(new MenuItemDescriptor("Map", WindowTypeEnum.MAP));
		viewDescriptors.add(new MenuItemDescriptor("Layers",
				WindowTypeEnum.LAYERS));
		viewDescriptors.add(new MenuItemDescriptor("Search Form",
				WindowTypeEnum.SEARCH_FORM));
		viewDescriptors.add(new MenuItemDescriptor("Results Results",
				WindowTypeEnum.SEARCH_RESULTS));
	}

	public void registerViews() {
		for (MenuItemDescriptor descriptor : viewDescriptors) {
			eventBus.fireEvent(new RegisterViewEvent(descriptor.getType()));
		}

		display.addMenu("Views", viewDescriptors);
		this.disableProjectMenuOptions();
	}

	@Override
	protected void onBind() {

		for (final MenuItemDescriptor view : viewDescriptors) {
			this.registerHandler(view.getMenuItem().addClickHandler(
					new ClickHandler() {

						@Override
						public void onClick(MenuItemClickEvent event) {
							eventBus
									.fireEvent(new ShowViewEvent(view.getType()));
						}
					}));
		}

		for (final MenuItemDescriptor item : fileMenuDescriptors) {
			if (item.getType() != null) {
				this.registerHandler(item.getMenuItem().addClickHandler(
						new ClickHandler() {

							@Override
							public void onClick(MenuItemClickEvent event) {
								eventBus.fireEvent(new OpenWinModalEvent(item
										.getType()));
							}
						}));
			}
		}

	}

	@Override
	public void retrieveWinData(WindowTypeEnum source, Map<String, Object> data) {
		if (source.equals(WindowTypeEnum.NEW)) {
			enableProjectMenuOptions();
		}
	}

	private void disableProjectMenuOptions() {
		// Disable views menu.
		List<String> names = new ArrayList<String>();
		names.add("Views");
		this.display.disableMenuButton(names);
		// Disable Save As menu option.
		List<String> ids = new ArrayList<String>();
		ids.add(fileMenuDescriptors.get(2).getId());
		ids.add(fileMenuDescriptors.get(3).getId());
		this.display.disableMenuItems(ids);
	}

	private void enableProjectMenuOptions() {
		// Disable views menu.
		List<String> names = new ArrayList<String>();
		names.add("Views");
		this.display.enableMenuButton(names);
		// Disable Save As menu option.
		List<String> ids = new ArrayList<String>();
		ids.add(fileMenuDescriptors.get(2).getId());
		ids.add(fileMenuDescriptors.get(3).getId());
		this.display.enableMenuItems(ids);
	}

	@Override
	protected void onRevealDisplay() {

	}

	@Override
	protected void onUnbind() {

	}

}
